/**
 * 远程授权服务器
 * 提供授权管理、验证、撤销等功能
 */

const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const WebSocket = require('ws');
const http = require('http');

const app = express();
const PORT = process.env.PORT || 3000;

// 中间件
app.use(cors());
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
app.use(express.static('public'));

// 数据存储路径
const DATA_DIR = path.join(__dirname, 'data');
const LICENSES_FILE = path.join(DATA_DIR, 'licenses.json');
const CLIENTS_FILE = path.join(DATA_DIR, 'clients.json');
const REVOKED_FILE = path.join(DATA_DIR, 'revoked.json');
const KEYS_DIR = path.join(__dirname, 'keys');

// 确保目录存在
[DATA_DIR, KEYS_DIR].forEach(dir => {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
});

// 初始化数据文件
[LICENSES_FILE, CLIENTS_FILE, REVOKED_FILE].forEach(file => {
  if (!fs.existsSync(file)) {
    fs.writeFileSync(file, '[]');
  }
});

// RSA密钥管理
let privateKey, publicKey;

function initializeKeys() {
  const privateKeyPath = path.join(KEYS_DIR, 'private.pem');
  const publicKeyPath = path.join(KEYS_DIR, 'public.pem');
  
  if (!fs.existsSync(privateKeyPath) || !fs.existsSync(publicKeyPath)) {
    console.log('生成新的RSA密钥对...');
    const { publicKey: pubKey, privateKey: privKey } = crypto.generateKeyPairSync('rsa', {
      modulusLength: 2048,
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem'
      }
    });
    
    fs.writeFileSync(privateKeyPath, privKey);
    fs.writeFileSync(publicKeyPath, pubKey);
    
    privateKey = privKey;
    publicKey = pubKey;
  } else {
    privateKey = fs.readFileSync(privateKeyPath, 'utf8');
    publicKey = fs.readFileSync(publicKeyPath, 'utf8');
  }
  
  console.log('服务器密钥初始化完成');
}

// 数据操作函数
function loadData(file) {
  try {
    return JSON.parse(fs.readFileSync(file, 'utf8'));
  } catch (error) {
    return [];
  }
}

function saveData(file, data) {
  fs.writeFileSync(file, JSON.stringify(data, null, 2));
}

// 授权生成函数
function generateLicense(options) {
  const {
    type = 'trial',
    machineId,
    customerName = '',
    duration = 30,
    unit = 'days',
    features = ['basic']
  } = options;
  
  // 根据授权类型强制设置持续时间
  let actualDuration = duration;
  let actualUnit = unit;
  
  // 根据授权类型设置正确的持续时间
  if (type === 'trial') {
    actualDuration = 30;
    actualUnit = 'days';
    console.log('服务端生成试用版授权：30天');
  } else if (type === 'standard') {
    actualDuration = 365;
    actualUnit = 'days';
    console.log('服务端生成标准版授权：365天');
  } else if (type === 'enterprise') {
    actualDuration = 36500; // 约100年，实际上是永久
    actualUnit = 'days';
    console.log('服务端生成企业版授权：永久');
  } else if (type === 'custom') {
    // 自定义类型使用传入的值
    console.log(`服务端生成自定义授权：${actualDuration} ${actualUnit}`);
  }
  
  const now = new Date();
  let expiryDate = new Date(now);
  
  // 计算过期时间
  switch (actualUnit) {
    case 'days':
      expiryDate.setDate(expiryDate.getDate() + actualDuration);
      break;
    case 'weeks':
      expiryDate.setDate(expiryDate.getDate() + (actualDuration * 7));
      break;
    case 'months':
      expiryDate.setMonth(expiryDate.getMonth() + actualDuration);
      break;
    case 'years':
      expiryDate.setFullYear(expiryDate.getFullYear() + actualDuration);
      break;
  }
  
  const licenseInfo = {
    id: `LIC-${Date.now()}-${crypto.randomBytes(4).toString('hex').toUpperCase()}`,
    type,
    machineId,
    customerName,
    issueDate: now.toISOString(),
    expiryDate: expiryDate.toISOString(),
    duration: actualDuration,  // 使用修正后的持续时间
    unit: actualUnit,          // 使用修正后的时间单位
    features,
    status: 'active',
    createdAt: now.toISOString()
  };
  
  // 生成签名
  const dataString = JSON.stringify(licenseInfo);
  const sign = crypto.createSign('SHA256');
  sign.update(dataString);
  const signature = sign.sign(privateKey, 'base64');
  
  // 组合授权码
  const licenseKey = Buffer.from(JSON.stringify({
    data: dataString,
    signature: signature
  })).toString('base64');
  
  // 保存到数据库
  const licenses = loadData(LICENSES_FILE);
  licenses.push({
    ...licenseInfo,
    licenseKey
  });
  saveData(LICENSES_FILE, licenses);
  
  return {
    licenseInfo,
    licenseKey,
    formattedKey: formatLicenseKey(licenseKey)
  };
}

// 格式化授权码
function formatLicenseKey(key) {
  return key.match(/.{1,5}/g)?.join('-') || key;
}

// 验证授权
function verifyLicense(licenseKey, machineId) {
  try {
    // 清理格式
    const cleanKey = licenseKey.replace(/[-\s]/g, '');
    
    // 解码
    const decoded = JSON.parse(Buffer.from(cleanKey, 'base64').toString());
    const licenseInfo = JSON.parse(decoded.data);
    
    // 验证签名
    const verify = crypto.createVerify('SHA256');
    verify.update(decoded.data);
    const isValid = verify.verify(publicKey, decoded.signature, 'base64');
    
    if (!isValid) {
      return { valid: false, reason: '签名验证失败' };
    }
    
    // 检查是否被撤销
    const revoked = loadData(REVOKED_FILE);
    if (revoked.includes(licenseInfo.id)) {
      return { valid: false, reason: '授权已被撤销' };
    }
    
    // 验证机器ID
    if (licenseInfo.machineId !== machineId) {
      return { valid: false, reason: '机器ID不匹配' };
    }
    
    // 验证有效期
    const now = new Date();
    const expiryDate = new Date(licenseInfo.expiryDate);
    if (now > expiryDate) {
      return { valid: false, reason: '授权已过期' };
    }
    
    // 计算剩余时间
    const remainingMs = expiryDate - now;
    const remainingDays = Math.floor(remainingMs / (1000 * 60 * 60 * 24));
    
    return {
      valid: true,
      licenseInfo,
      remainingDays,
      remainingTime: {
        days: remainingDays,
        formatted: `${remainingDays}天`
      },
      features: licenseInfo.features
    };
  } catch (error) {
    return { valid: false, reason: error.message };
  }
}

// ========== API 路由 ==========

// 获取公钥
app.get('/api/public-key', (req, res) => {
  res.json({ publicKey });
});

// 生成授权
app.post('/api/generate-license', (req, res) => {
  try {
    const license = generateLicense(req.body);
    res.json({ success: true, data: license });
  } catch (error) {
    res.status(400).json({ success: false, error: error.message });
  }
});

// 验证授权
app.post('/api/verify-license', (req, res) => {
  const { licenseKey, machineId } = req.body;
  
  if (!licenseKey || !machineId) {
    return res.status(400).json({ 
      success: false, 
      error: '缺少必要参数' 
    });
  }
  
  const result = verifyLicense(licenseKey, machineId);
  res.json({ success: result.valid, data: result });
});

// 撤销授权
app.post('/api/revoke-license', (req, res) => {
  const { licenseId, reason } = req.body;
  
  if (!licenseId) {
    return res.status(400).json({ 
      success: false, 
      error: '缺少授权ID' 
    });
  }
  
  const revoked = loadData(REVOKED_FILE);
  if (!revoked.includes(licenseId)) {
    revoked.push(licenseId);
    saveData(REVOKED_FILE, revoked);
  }
  
  // 记录撤销原因
  const licenses = loadData(LICENSES_FILE);
  const licenseIndex = licenses.findIndex(l => l.id === licenseId);
  if (licenseIndex !== -1) {
    licenses[licenseIndex].status = 'revoked';
    licenses[licenseIndex].revokedAt = new Date().toISOString();
    licenses[licenseIndex].revokeReason = reason || '未指定';
    saveData(LICENSES_FILE, licenses);
  }
  
  res.json({ success: true, message: '授权已撤销' });
});

// 远程撤销客户端授权
app.post('/api/remote-revoke', (req, res) => {
  const { machineId, reason } = req.body;
  
  if (!machineId) {
    return res.status(400).json({ 
      success: false, 
      error: '缺少机器ID' 
    });
  }
  
  // 查找客户端
  const clients = loadData(CLIENTS_FILE);
  const client = clients.find(c => c.machineId === machineId);
  
  if (!client) {
    return res.status(404).json({
      success: false,
      error: '未找到指定客户端'
    });
  }
  
  // 如果客户端有授权信息，将其授权ID添加到撤销列表
  let licenseId = null;
  if (client.licenseInfo && client.licenseInfo.id) {
    licenseId = client.licenseInfo.id;
    
    // 添加到撤销列表
    const revoked = loadData(REVOKED_FILE);
    if (!revoked.includes(licenseId)) {
      revoked.push(licenseId);
      saveData(REVOKED_FILE, revoked);
    }
    
    // 更新授权状态
    const licenses = loadData(LICENSES_FILE);
    const licenseIndex = licenses.findIndex(l => l.id === licenseId);
    if (licenseIndex !== -1) {
      licenses[licenseIndex].status = 'revoked';
      licenses[licenseIndex].revokedAt = new Date().toISOString();
      licenses[licenseIndex].revokeReason = reason || '远程撤销';
      saveData(LICENSES_FILE, licenses);
    }
  }
  
  // 向客户端发送撤销消息
  const message = {
    type: 'revoke_license',
    machineId: machineId,
    licenseId: licenseId,
    reason: reason || '管理员撤销',
    timestamp: Date.now()
  };
  
  // 尝试通过WebSocket发送撤销指令
  const sent = sendMessageToClient(machineId, message);
  
  res.json({ 
    success: true, 
    message: '撤销指令已发送',
    delivered: sent,
    licenseId: licenseId
  });
});

// 获取所有授权
app.get('/api/licenses', (req, res) => {
  const licenses = loadData(LICENSES_FILE);
  res.json({ success: true, data: licenses });
});

// 获取单个授权详情
app.get('/api/license/:id', (req, res) => {
  const licenseId = req.params.id;
  const licenses = loadData(LICENSES_FILE);
  const license = licenses.find(l => l.id === licenseId);
  
  if (!license) {
    return res.status(404).json({
      success: false,
      error: '未找到授权'
    });
  }
  
  res.json({ success: true, data: license });
});

// 获取客户端详情
app.get('/api/client/:id', (req, res) => {
  const machineId = req.params.id;
  const clients = loadData(CLIENTS_FILE);
  const client = clients.find(c => c.machineId === machineId);
  
  if (!client) {
    return res.status(404).json({
      success: false,
      error: '未找到客户端'
    });
  }
  
  res.json({ success: true, data: client });
});

// 获取连接的客户端
app.get('/api/clients', (req, res) => {
  const clients = loadData(CLIENTS_FILE);
  res.json({ success: true, data: clients });
});

// 客户端注册/心跳
app.post('/api/client/register', (req, res) => {
  const { machineId, systemInfo, licenseId } = req.body;
  
  if (!machineId) {
    return res.status(400).json({ 
      success: false, 
      error: '缺少机器ID' 
    });
  }
  
  const clients = loadData(CLIENTS_FILE);
  const existingIndex = clients.findIndex(c => c.machineId === machineId);
  
  const clientInfo = {
    machineId,
    systemInfo,
    licenseId,
    lastSeen: new Date().toISOString(),
    status: 'online'
  };
  
  if (existingIndex !== -1) {
    clients[existingIndex] = { ...clients[existingIndex], ...clientInfo };
  } else {
    clientInfo.firstSeen = new Date().toISOString();
    clients.push(clientInfo);
  }
  
  saveData(CLIENTS_FILE, clients);
  res.json({ success: true, message: '客户端已注册' });
});

// 统计信息
app.get('/api/stats', (req, res) => {
  const licenses = loadData(LICENSES_FILE);
  const clients = loadData(CLIENTS_FILE);
  const revoked = loadData(REVOKED_FILE);
  
  const now = new Date();
  const activeClients = clients.filter(c => {
    const lastSeen = new Date(c.lastSeen);
    const diff = now - lastSeen;
    return diff < 5 * 60 * 1000; // 5分钟内活跃
  });
  
  res.json({
    success: true,
    data: {
      totalLicenses: licenses.length,
      activeLicenses: licenses.filter(l => l.status === 'active').length,
      revokedLicenses: revoked.length,
      totalClients: clients.length,
      onlineClients: activeClients.length,
      licenseTypes: {
        trial: licenses.filter(l => l.type === 'trial').length,
        standard: licenses.filter(l => l.type === 'standard').length,
        enterprise: licenses.filter(l => l.type === 'enterprise').length,
        custom: licenses.filter(l => l.type === 'custom').length
      }
    }
  });
});

// 创建HTTP服务器
const server = http.createServer(app);

// WebSocket服务器用于实时通信
const wss = new WebSocket.Server({ server });

const wsClients = new Map();
const connectedClients = new Map(); // 存储已连接客户端信息，按照machineId索引

wss.on('connection', (ws, req) => {
  const clientId = crypto.randomBytes(8).toString('hex');
  let clientMachineId = null;
  
  ws.on('message', (message) => {
    try {
      const data = JSON.parse(message);
      console.log('收到WebSocket消息:', data.type);
      
      switch (data.type) {
        case 'register':
          // 设置客户端信息
          clientMachineId = data.machineId;
          
          // 将客户端信息存储在两个映射中
          wsClients.set(clientId, {
            ws,
            machineId: data.machineId,
            systemInfo: data.systemInfo,
            licenseInfo: data.licenseInfo,
            lastSeen: new Date()
          });
          
          // 使用machineId作为键存储客户端信息
          connectedClients.set(data.machineId, {
            clientId,
            systemInfo: data.systemInfo,
            licenseInfo: data.licenseInfo,
            lastSeen: new Date()
          });
          
          // 更新客户端列表 - 存储到数据文件
          updateClientInDatabase(data);
          
          // 广播客户端列表更新
          broadcastClientList();
          console.log(`客户端已注册，ID: ${clientId}, 机器ID: ${data.machineId}`);
          break;
          
        case 'heartbeat':
          // 更新最后活跃时间
          if (wsClients.has(clientId)) {
            const client = wsClients.get(clientId);
            client.lastSeen = new Date();
            
            // 同时更新另一个映射
            if (client.machineId && connectedClients.has(client.machineId)) {
              connectedClients.get(client.machineId).lastSeen = new Date();
            }
            
            // 更新数据库中的最后活跃时间
            const clients = loadData(CLIENTS_FILE);
            const clientIndex = clients.findIndex(c => c.machineId === client.machineId);
            if (clientIndex !== -1) {
              clients[clientIndex].lastSeen = new Date().toISOString();
              clients[clientIndex].status = 'online';
              saveData(CLIENTS_FILE, clients);
            }
          }
          break;
          
        case 'revocation_confirmation':
          // 客户端确认已撤销授权
          console.log(`客户端确认撤销: ${data.machineId}, 授权ID: ${data.licenseId}`);
          // 可以在这里更新撤销状态
          break;
          
        case 'license_verified':
          // 客户端验证授权成功，更新授权信息
          if (wsClients.has(clientId) && data.licenseInfo) {
            const client = wsClients.get(clientId);
            client.licenseInfo = data.licenseInfo;
            
            if (client.machineId && connectedClients.has(client.machineId)) {
              connectedClients.get(client.machineId).licenseInfo = data.licenseInfo;
            }
            
            // 更新数据库
            updateClientInDatabase({
              machineId: client.machineId,
              systemInfo: client.systemInfo,
              licenseInfo: data.licenseInfo
            });
            
            // 广播更新
            broadcastClientList();
          }
          break;
      }
    } catch (error) {
      console.error('WebSocket消息处理错误:', error);
    }
  });
  
  ws.on('close', () => {
    console.log(`客户端断开连接: ${clientId}`);
    // 从映射中移除客户端
    if (wsClients.has(clientId)) {
      const client = wsClients.get(clientId);
      if (client.machineId) {
        connectedClients.delete(client.machineId);
        
        // 更新数据库中的状态
        const clients = loadData(CLIENTS_FILE);
        const clientIndex = clients.findIndex(c => c.machineId === client.machineId);
        if (clientIndex !== -1) {
          clients[clientIndex].status = 'offline';
          clients[clientIndex].lastSeen = new Date().toISOString();
          saveData(CLIENTS_FILE, clients);
        }
      }
      wsClients.delete(clientId);
    }
    
    broadcastClientList();
  });
  
  // 发送欢迎消息
  ws.send(JSON.stringify({
    type: 'welcome',
    clientId,
    message: '已连接到授权服务器'
  }));
});

// 更新客户端信息到数据库
function updateClientInDatabase(data) {
  const clients = loadData(CLIENTS_FILE);
  const existingIndex = clients.findIndex(c => c.machineId === data.machineId);
  
  const clientInfo = {
    machineId: data.machineId,
    systemInfo: data.systemInfo,
    licenseInfo: data.licenseInfo,
    lastSeen: new Date().toISOString(),
    status: 'online'
  };
  
  if (existingIndex !== -1) {
    // 更新现有客户端
    clients[existingIndex] = { ...clients[existingIndex], ...clientInfo };
  } else {
    // 添加新客户端
    clientInfo.firstSeen = new Date().toISOString();
    clients.push(clientInfo);
  }
  
  saveData(CLIENTS_FILE, clients);
}

// 广播客户端列表
function broadcastClientList() {
  // 准备要广播的客户端信息
  const clientList = Array.from(wsClients.values()).map(client => ({
    machineId: client.machineId,
    systemInfo: client.systemInfo,
    licenseInfo: client.licenseInfo,
    lastSeen: client.lastSeen || new Date(),
    status: 'online'
  }));
  
  // 向所有连接的管理界面发送更新
  const message = JSON.stringify({
    type: 'clientList',
    data: clientList
  });
  
  wsClients.forEach(client => {
    if (client.ws.readyState === WebSocket.OPEN) {
      client.ws.send(message);
    }
  });
}

// 向指定机器ID的客户端发送消息
function sendMessageToClient(machineId, message) {
  // 查找客户端
  if (!connectedClients.has(machineId)) {
    console.log(`未找到客户端: ${machineId}`);
    return false;
  }
  
  const clientInfo = connectedClients.get(machineId);
  const clientId = clientInfo.clientId;
  
  if (!wsClients.has(clientId)) {
    console.log(`客户端已断开连接: ${machineId}`);
    return false;
  }
  
  const client = wsClients.get(clientId);
  
  if (client.ws.readyState !== WebSocket.OPEN) {
    console.log(`客户端连接已关闭: ${machineId}`);
    return false;
  }
  
  // 发送消息
  try {
    client.ws.send(JSON.stringify(message));
    console.log(`已向客户端 ${machineId} 发送消息: ${message.type}`);
    return true;
  } catch (error) {
    console.error(`向客户端 ${machineId} 发送消息失败:`, error);
    return false;
  }
}

// 定期清理离线客户端
setInterval(() => {
  const now = new Date();
  const clients = loadData(CLIENTS_FILE);
  
  clients.forEach(client => {
    const lastSeen = new Date(client.lastSeen);
    const diff = now - lastSeen;
    
    if (diff > 10 * 60 * 1000) { // 10分钟无响应
      client.status = 'offline';
    }
  });
  
  saveData(CLIENTS_FILE, clients);
}, 60000); // 每分钟检查一次

// 初始化
initializeKeys();

// 启动服务器
server.listen(PORT, () => {
  console.log(`
╔════════════════════════════════════════╗
║     License Guard 远程授权服务器        ║
║                                        ║
║     服务器已启动在端口 ${PORT}            ║
║     管理面板: http://localhost:${PORT}    ║
║                                        ║
║     API端点:                           ║
║     - POST /api/generate-license       ║
║     - POST /api/verify-license         ║
║     - POST /api/revoke-license         ║
║     - GET  /api/licenses               ║
║     - GET  /api/clients                ║
║     - GET  /api/stats                  ║
║                                        ║
║     WebSocket: ws://localhost:${PORT}     ║
╚════════════════════════════════════════╝
  `);
});

module.exports = app;
